package product.service.impl;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import product.domain.Category;
import product.mapper.CategoryBrandRelationMapper;
import product.mapper.CategoryMapper;
import product.service.CategoryService;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author panghu
 * @description 针对表【pms_category(商品三级分类)】的数据库操作Service实现
 * @createDate 2023-03-04 21:03:08
 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {

    @Autowired
    private CategoryBrandRelationMapper categoryBrandRelationMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    @Transactional
    public List<Category> findAllCategoryList() {
        // 首先查看缓存是否有
        String categoryKey = "product:categoryList";
        String redisCategoryList = redisTemplate.opsForValue().get(categoryKey);
        if (!ObjectUtils.isEmpty(redisCategoryList)) {
            // 命中到空值了
            // 查询数据库
            List<Category> list = JSONUtil.toList(redisCategoryList, Category.class);
            if (!ObjectUtils.isEmpty(list)) {
                // 返回缓存
                return list;
            }
        }
        // 设置锁
        Boolean setNx = redisTemplate.opsForValue().setIfAbsent("setNx", "1", 10, TimeUnit.SECONDS);
        if (BooleanUtil.isTrue(setNx)) {
            // 先查缓存
            String s = redisTemplate.opsForValue().get(categoryKey);
            /*if (ObjectUtils.isEmpty(s)) {
                // 命中到空值了
                return null;
            }
            List<Category> redisList = JSONUtil.toList(s, Category.class);
            if (!ObjectUtils.isEmpty(redisList)) {
                // 返回缓存
                return redisList;
            }*/
            if (!ObjectUtils.isEmpty(redisCategoryList)) {
                // 命中到空值了
                // 查询数据库
                List<Category> list = JSONUtil.toList(redisCategoryList, Category.class);
                if (!ObjectUtils.isEmpty(list)) {
                    // 返回缓存
                    return list;
                }
            }
            // 全部的目录
            List<Category> categories = baseMapper.selectList(null);
            if (ObjectUtils.isEmpty(categories)) {
                // 数据库中不存在，给redis中缓存空值并设置过期时间
                redisTemplate.opsForValue().set(categoryKey, "", 1000, TimeUnit.MINUTES);
                return null;
            }
            // 组织目录
            List<Category> categoryList = categories.stream()
                    // 获取所有的一级目录，ParentCid===0
                    .filter(category -> category.getParentCid() == 0)
                    // 设置他的子目录
                    .peek(category -> category.setChildren(getChildren(category, categories)))
                    // 排序
                    .sorted(Comparator.comparingInt(menu -> (menu.getSort() == null ? 0 : menu.getSort())))
                    .collect(Collectors.toList());
            // 存入redis缓存
            redisTemplate.opsForValue().set(categoryKey, JSON.toJSONString(categoryList), 1, TimeUnit.DAYS);
            // 删除锁
            redisTemplate.delete("setNx");
        }
        return null;
    }

    @Override
    public boolean removeCategoryByIds(List<Long> ids) {
        //todo 有关联的节点不能删除
        int result = baseMapper.deleteBatchIds(ids);
        return result > 0;
    }

    @Override
    @Transactional
    public boolean updateCascade(Category category) {
        boolean result = this.updateById(category);
        categoryBrandRelationMapper.updateCatNameByCatId(category.getCatId(), category.getName());
        // todo 更新缓存
        String categoryKey = "product:categoryList";
        // 全部的目录
        List<Category> categories = baseMapper.selectList(null);
        // 组织目录
        List<Category> categoryList = categories.stream()
                // 获取所有的一级目录，ParentCid===0
                .filter(item -> item.getParentCid() == 0)
                // 设置他的子目录
                .peek(item -> item.setChildren(getChildren(item, categories)))
                // 排序
                .sorted(Comparator.comparingInt(menu -> (menu.getSort() == null ? 0 : menu.getSort())))
                .collect(Collectors.toList());
        redisTemplate.opsForValue().set(categoryKey, JSON.toJSONString(categoryList), 1, TimeUnit.DAYS);
        return result;
    }

    @Override
    public String findCategoryNameById(Long categoryId) {
        return this.baseMapper.selectById(categoryId).getName();
    }

    @Override
    public List<Category> findCategoryPath(Long categoryId) {
        List<Category> categoryList = new LinkedList<>();
        Category category = this.baseMapper.selectById(categoryId);
        categoryList.add(category);
        getParentCat(categoryList, category);
        return categoryList;
    }

    private void getParentCat(List<Category> categoryList, Category category) {
        if (category.getParentCid() != 0) {
            Category parentCat = this.baseMapper.selectById(category.getParentCid());
            categoryList.add(parentCat);
            getParentCat(categoryList, parentCat);
        }
    }

    /**
     * 找到当前目录的所有子目录
     *
     * @param category   当前目录
     * @param categories 所有目录
     * @return 子目录
     */
    private List<Category> getChildren(Category category, List<Category> categories) {
        return categories.stream()
                .filter(category1 -> Objects.equals(category1.getParentCid(), category.getCatId()))
                .peek(category1 -> category1.setChildren(getChildren(category1, categories)))
                .sorted(Comparator.comparingInt(menu -> (menu.getSort() == null ? 0 : menu.getSort())))
                .collect(Collectors.toList());
    }
}




